home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
COMM
/
MSKRMSRC.ARJ
/
MSNICM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-24
|
7KB
|
301 lines
/* File MSNICM.C
* ICMP packet processor
*
* Copyright (C) 1991, University of Waterloo.
* Copyright (C) 1991, Trustees of Columbia University in the
* City of New York. Permission is granted to any individual or
* institution to use, copy, or redistribute this software as long as
* it is not sold for profit and this copyright notice is retained.
*
* Original version created by Erick Engelke of the University of
* Waterloo, Waterloo, Ontario, Canada.
* Adapted and modified for MS-DOS Kermit by Joe R. Doupnik,
* Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
*
* Last edit
* 6 Sept 1991
*/
#include "msntcp.h"
#include "msnlib.h"
/*
* ICMP - RFC 792
*/
static byte *unreach[] = {
"Network Unreachable",
"Host Unreachable",
"Protocol Unreachable",
"Port Unreachable",
"Fragmentation needed and DF set",
"Source Route Failed" };
static byte *exceed[] = {
"TTL exceeded in transit",
"Frag ReAsm time exceeded" };
static byte *redirect[] = {
"Redirect for Network",
"Redirect for Host",
"Redirect for TOS and Network",
"Redirect for TOS and Host" };
/* constants */
typedef struct icmp_unused {
byte type;
byte code;
word checksum;
longword unused;
in_Header ip;
byte spares[ 8 ];
};
typedef struct icmp_pointer {
byte type;
byte code;
word checksum;
byte pointer;
byte unused[ 3 ];
in_Header ip;
};
typedef struct icmp_ip {
byte type;
byte code;
word checksum;
longword ipaddr;
in_Header ip;
};
typedef struct icmp_echo {
byte type;
byte code;
word checksum;
word identifier;
word sequence;
};
typedef struct icmp_timestamp {
byte type;
byte code;
word checksum;
word identifier;
word sequence;
longword original; /* original timestamp */
longword receive; /* receive timestamp */
longword transmit; /* transmit timestamp */
};
typedef struct icmp_info {
byte type;
byte code;
word checksum;
word identifier;
word sequence;
};
typedef union {
struct icmp_unused unused;
struct icmp_pointer pointer;
struct icmp_ip ip;
struct icmp_echo echo;
struct icmp_timestamp timestamp;
struct icmp_info info;
} icmp_pkt;
typedef struct pkt {
in_Header in;
icmp_pkt icmp;
in_Header data;
};
static word icmp_id = 0;
static longword ping_hcache = 0L; /* host */
static longword ping_tcache = 0L; /* time */
static longword ping_number = 0L;
extern word debug_on;
extern word sourcequench; /* non-zero if rcv'd ICMP S. Q. */
void
icmp_init() /* reinit all local statics */
{
ping_hcache = ping_tcache = ping_number = 0L;
icmp_id = 0;
return;
}
longword
chk_ping(longword host, longword *ptr)
{
if ((ping_hcache == host) && (ptr != NULL))
{
ping_hcache = 0xffffffffL;
*ptr = ping_number;
return (ping_tcache);
}
return (0xffffffffL);
}
void
icmp_print(byte *msg)
{
if (msg == NULL) return;
outs("\n\r ICMP: ");
outs(msg);
}
struct pkt *
icmp_Format(longword destip)
{
eth_address dest;
/* we use arp rather than supplied hardware address */
/* after first ping this will still be in cache */
if (arp_resolve(destip, dest) == 0)
return (NULL); /* unable to find address */
return ((struct pkt*)eth_formatpacket(dest, 8));
}
/*
* icmp_Reply - format a reply packet
* - note that src and dest are NETWORK order not host!!!!
*/
int
icmp_Reply(struct pkt *p, longword src, longword dest, int icmp_length)
{
if (p == NULL) return (0); /* failure */
/* finish the icmp checksum portion */
p->icmp.unused.checksum = 0;
p->icmp.unused.checksum = ~checksum(&p->icmp, icmp_length);
/* encapsulate into a nice IP packet */
p->in.hdrlen_ver = 0x45;
p->in.length = intel16(sizeof(in_Header) + icmp_length);
p->in.tos = 0;
p->in.identification = intel16(icmp_id++); /* not using IP id */
p->in.frag = 0;
p->in.ttl = 250;
p->in.proto = ICMP_PROTO;
p->in.checksum = 0;
p->in.source = src;
p->in.destination = dest;
p->in.checksum = ~checksum(&p->in, sizeof(in_Header));
return (eth_send(intel16(p->in.length))); /* send the reply */
}
int
icmp_handler(in_Header *ip)
{
register icmp_pkt *icmp, *newicmp;
struct pkt *pkt;
int len, code;
in_Header *ret;
len = in_GetHdrlenBytes(ip);
icmp = (icmp_pkt *)((byte *)ip + len);
len = intel16(ip->length) - len;
if (checksum(icmp, len) != 0xffff)
return (0); /* 0 = failure */
code = icmp->unused.code;
switch (icmp->unused.type)
{
case 0: /* icmp echo reply received */
/* icmp_print("received icmp echo receipt"); */
/* check if we were waiting for it */
ping_hcache = intel(ip->source);
ping_tcache = set_timeout(1) -
*(longword *)(&icmp->echo.identifier);
if (ping_tcache > 0xffffffffL)
ping_tcache += 0x1800b0L;
ping_number =
*(longword*)(((byte*)(&icmp->echo.identifier)) + 4);
/* do more */
break;
case 3 : /* destination unreachable message */
if (code < 6)
{
icmp_print(unreach[code]);
/* handle udp or tcp socket */
ret = (in_Header *)(icmp) + sizeof(icmp_pkt);
if (ret->proto == TCP_PROTO)
tcp_cancel(ret);
if (ret->proto == UDP_PROTO)
udp_cancel(ret);
}
break;
case 4: /* source quench */
/* icmp_print("Source Quench"); */
sourcequench = 1; /* set flag, used in TCP code */
break;
case 5: /* redirect */
if (code < 4)
{
arp_register(intel(icmp->ip.ipaddr),
intel(icmp->ip.ip.destination));
icmp_print(redirect[code]);
}
break;
case 8: /* icmp echo request */
/* icmp_print("PING requested of us"); */
/* do arp and create packet */
/* format the packet with the request's hardware address */
pkt = (struct pkt*)(eth_formatpacket(
(eth_address *)eth_hardware(ip), 8));
newicmp = &pkt->icmp;
bcopy(icmp, newicmp, len);
newicmp->echo.type = 0;
newicmp->echo.code = code;
/* use supplied ip values in case we ever multi-home */
/* note that ip values are still in network order */
icmp_Reply(pkt, ip->destination, ip->source, len);
/* icmp_print("PING reply sent"); */
break;
case 11: /* time exceeded message */
if (code < 2)
icmp_print(exceed[code]);
break;
case 12: /* parameter problem message */
icmp_print("IP Parameter problem");
break;
case 13: /* timestamp message */
/* icmp_print("Timestamp message"); */
/* send reply */
break;
case 14: /* timestamp reply */
/* icmp_print("Timestamp reply"); */
/* should store */
break;
case 15: /* info request */
/* icmp_print("Info requested"); */
/* send reply */
break;
case 16: /* info reply */
/* icmp_print("Info reply"); */
break;
} /* end of switch */
return (1); /* status of success */
}